#pragma once // 防止头文件被多次包含

// 包含标准输入输出流库，用于日志和错误输出
#include <iostream>
// 包含字符串处理库，用于IP地址、消息等字符串操作
#include <string>
// 包含C错误码定义，如 errno
#include <cerrno>
// 包含C风格字符串处理函数，如 strerror, bzero
#include <cstring> // 注意：在C++中推荐使用 <cstring> 而不是 <string.h>
// 包含C标准库函数，如 exit, stoi
#include <cstdlib>
// 包含 strings.h，提供 bzero (虽然在现代C++中更推荐用 memset)
#include <strings.h> // POSIX.1-2001 and POSIX.1-2008 require <strings.h>
// 包含系统数据类型定义
#include <sys/types.h>
// 包含套接字编程相关函数和数据结构
#include <sys/socket.h>
// 包含IP地址转换函数，如 inet_addr, htons
#include <arpa/inet.h>
// 包含Internet地址族相关数据结构
#include <netinet/in.h>
// 包含函数对象和绑定器，用于回调函数封装
#include <functional>
// 包含自定义的日志系统头文件
#include "Log.hpp"
// 包含自定义的网络地址封装类头文件
#include "InetAddr.hpp"

enum
{
    SOCKET_ERROR = -1,
    BIND_ERROR,
    USAGE_ERROR
};
const static int defaultfd = -1;

using handler_message_t = std::function<void(int sockfd, const std::string message, const InetAddr who)>;

class UdpServer
{
public:
    UdpServer(uint16_t port, handler_message_t handler_message)
        : _sockfd(defaultfd), _port(port), _isrunning(false), _handler_message(handler_message)
    {
    }
    void InitServer()
    {
        // 1.创建套接字
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(FATAL, "socket error,%s,%d\n", strerror(errno), errno);
            exit(SOCKET_ERROR);
        }
        LOG(INFO, "套接字创建成功!:d\n", _sockfd);
        // 2.填充服务器的地址信息
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET; // IPV4
        // 记忆技巧：
        // AF 可以理解为 Address Family，即地址族，指的是协议族的类型。
        // INET 指的是 Internet，表示互联网协议族，通常是指基于 IPv4 或 IPv6 的协议。
        local.sin_port = htons(_port);      // 讲主机字节序转换成网络字节序，因为在网络上传输必须用后者
        local.sin_addr.s_addr = INADDR_ANY; // 服务器监听本机所有网络接口上的请求

        // 3. 绑定地址结构体到套接字上
        int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(FATAL, "绑定出错,%s,%d\n", strerror(errno), errno);
            exit(BIND_ERROR);
        }
        LOG(INFO, "套接字绑定成功\n");
    }

    // 启动服务器，死循环不断接受客户端的请求
    void Start()
    {
        _isrunning = true;
        while (true)
        {
            // 准备接收数据
            char message[1024];
            struct sockaddr_in peer; // 客户端的地址信息
            socklen_t len = sizeof(peer);
            ssize_t n = recvfrom(_sockfd, message, sizeof(message) - 1, 0, (struct sockaddr *)&peer, &len); // 缓冲区大小减1为末尾空字符留空间。（末尾放\0）
            if (n > 0)
            {
                message[n] = 0; //'\0'也可以
                InetAddr addr(peer);
                LOG(DEBUG, "得到了一条消息来自[%s:%d]:%s\n", addr.Ip().c_str(), addr.Port(), message);
                // 调用注册的消息处理回调函数，将接收到的数据和发送方信息传递给它
                _handler_message(_sockfd, message, addr);
            }
            else if (n == 0)
            {
                LOG(INFO, "对端关闭\n");
                break;
            }
            else
            {
                LOG(ERROR, "recvfrom error:%s\n", strerror(errno));
                break;
            }
        }
        _isrunning = false;
    }

    ~UdpServer()
    {
        LOG(INFO, "UdpServer析构函数\n");
    }

private:
    int _sockfd;
    uint16_t _port;
    bool _isrunning;
    handler_message_t _handler_message;
};